// 如果我想将this指向特定的对象，但是不希望这个函数式这个对象的属性？
// 我们可以考虑使用call apply

(function () {
    function foo() {
        console.log(this.a);
    }

    var obj = {
        a: 2
    };

    foo.call(obj); // 2
})();


//使用call绑定的this是一个硬绑定，无论外部的上下文如何变化，他的this绑定都不会发生改变
(function () {
    function foo() {
        console.log(this.a);
    }

    var obj = {
        a: 2
    };

    var bar = function () {
        foo.call(obj);
    };

    bar(); // 2
    setTimeout(bar, 100); // 2

    // `bar` hard binds `foo`'s `this` to `obj`
    // so that it cannot be overriden
    bar.call(window); // 2
})();


/* (function () {
    console.log("try it myself");
    var obj={
        a:"in the obj"
    }
    function foo() {
        console.log(this.a);
    }
    function doFun(fn){
        fn.call(obj)
    }
    doFun(foo);
    console.log("try it myself end");
})(); */


// 使用硬绑定典型的模式
(function () {
    console.log("pattern one");

    function foo(something) {
        console.log(this.a, something);
        return this.a + something;
    }

    var obj = {
        a: 2
    };

    //看成是一种管道
    var bar = function () {
        return foo.apply(obj, arguments);
    };

    var b = bar(3); // 2 3
    console.log(b); // 5
    console.log("pattern one end");
})();

// 使用硬绑定典型的模式：制作一个用于复用的helper
(function () {
    console.log("pattern two");
    
    function foo(something) {
        console.log(this.a, something);
        return this.a + something;
    }
    
    // 制造出一个helper用来绑定运行环境，这个其实也是一个闭包
    function bind(obj, fn) {
        return function () {
            return fn.apply(obj, arguments);
        }
    }
    
    var obj={
        a:5
    };
    
    var fn1=bind(obj,foo);
    console.log(fn1(12));

    console.log("pattern two end");
})();


// 除了使用call和apply可以修改this的绑定，在es5中还提供了bind方法
(function () {
    function foo(something) {
        console.log( this.a, something );
        return this.a + something;
    }
    
    var obj = {
        a: 2
    };
    
    var bar = foo.bind( obj );//感觉有了这个方法连helper都省了
    
    var b = bar( 3 ); // 2 3
    console.log( b ); // 5
})();


// 很多库api支持用户在调用的设置api
(function () {
    function foo(el) {
        console.log( el, this.id );
    }
    
    var obj = {
        id: "awesome"
    };
    
    // use `obj` as `this` for `foo(..)` calls
    [1, 2, 3].forEach( foo, obj ); // 1 awesome  2 awesome  3 awesome
})();





console.log("===========over===========");